import { SettingOutlined } from '@ant-design/icons'
import { Pagination } from 'antd'
import { filter, find, findIndex, isEmpty, orderBy } from 'lodash-es'
import { useEffect, useRef, useState } from 'react'
import AutoSizer from 'react-virtualized-auto-sizer'

import ResizableTable from '../ResizableTable'

import ConfigModal from './ConfigModal'

/**
 * @typedef {Object} ColumnsProps
 * @property {boolean} [exclude] 是否排除
 */

/**
 * @typedef {Object} OtherProps
 * @property {string} [configKey] 表格的唯一key，本地根据key存放配置信息
 * @property {Boolean} [showIndex] 显示序号，默认true
 * @property {boolean} [showConfig] 是否显示设置
 * @property {boolean} [autoSizeHeight] 是否自动调整高度，如果设置了false，则需要给table的scroll.y设置，不设置的时候默认为500
 * @property {Array<ColumnsProps>} [columns] 表格项配置
 * @property {import("react")} [beforePagination] 页码前面的内容
 */

/**
 * @typedef {import("antd/es/table").TableProps & OtherProps} ConfigableTableProps
 */

/**
 * 自定义table，支持表格头配置
 * @param {ConfigableTableProps} props
 * @returns
 */
const ConfigableTable = props => {
  const {
    configKey,
    showIndex,
    showConfig = true,
    className,
    columns: propCols,
    scroll,
    beforePagination,
    pagination,
    dataSource,
    autoSizeHeight = true,
  } = props
  const [columns, setColumns] = useState([])
  const [configColumns, setConfigColumns] = useState([]) // 可配置部分
  const [tHeadHeight, setTHeadHeight] = useState(35)

  const tableWrapperRef = useRef()

  const calcTheadHeight = () => {
    const wrapper = tableWrapperRef.current
    if (wrapper) {
      const theadNode = wrapper.querySelector('thead')
      const tHeadHeight = theadNode ? theadNode.offsetHeight : 35
      setTHeadHeight(tHeadHeight)
    }
  }

  const initData = () => {
    let clonedCols = [...propCols] // 保持propCols不变
    // 唯一键统一
    clonedCols = clonedCols.map(col => {
      const uniqKey = JSON.stringify(col.key || col.dataIndex)
      let children = undefined
      if (!isEmpty(col.children)) {
        children = col.children.map(item => {
          return { ...item, key: JSON.stringify(item.key || item.dataIndex) }
        })
      }
      return { ...col, key: uniqKey, children }
    })
    // 过滤 exclude 的列（业务排除，常见于不同tab）
    let filteredColumns = filter(clonedCols, col => !col.exclude).map(col => ({
      ...col,
      width: col.width || (col.key.includes('Time') ? 180 : 120),
      // 记录代码自身的宽度，在未出现滚动条时，设置宽度的还可以按设置的值展示
      sysWidth: col.width,
    }))
    // 查找本地存储的列数据
    const localConfig = localStorage.getItem(`tableConfig_${configKey}`)
    if (localConfig) {
      const localTableCols = JSON.parse(localConfig)
      // 固定项不可配置
      // const leftFixedCols = filter(filteredColumns, col => col.fixed === 'left')
      // const rightFixedCols = filter(filteredColumns, col => col.fixed === 'right')
      // let configableCols = filter(filteredColumns, col => !col.fixed)
      // 对比本地数据
      filteredColumns.forEach((originalCol, originalIndex) => {
        const target = find(localTableCols, col => originalCol.key === col.key)
        const targetIndex = findIndex(localTableCols, col => originalCol.key === col.key)
        if (target) {
          // 注：会出现找不到的情形（迭代新增/修改字段）
          originalCol.width = target.width || originalCol.width // 以配置过的数据为准
          originalCol.order = targetIndex
          originalCol.hide = target.hide
          if (!isEmpty(originalCol.children) && !isEmpty(target.children)) {
            originalCol.children.forEach((item, itemIndex) => {
              const targetItem = target.children.find(localItem => localItem.key === item.key)
              const targetItemIndex = target.children.findIndex(localItem => localItem.key === item.key)
              if (targetItem) {
                item.width = targetItem.width || item.width // 以配置过的数据为准
                item.order = targetItemIndex
                item.hide = targetItem.hide
              } else {
                item.order = itemIndex
              }
            })
          }
        } else {
          originalCol.order = originalIndex
        }
      })
      // 排序
      filteredColumns = orderBy(filteredColumns, 'order')
      // filteredColumns = [...leftFixedCols, ...configableCols, ...rightFixedCols]
    }
    // console.debug('filteredColumns', filteredColumns)
    // 设置可配置列
    // const configableCols = filteredColumns.filter(col => !col.fixed)
    // setConfigColumns(cloneDeep(configableCols))
    setConfigColumns(filteredColumns)
    const visibleColumns = []
    filteredColumns.forEach(item => {
      const _item = { ...item }
      if (_item.hide) return
      if (!isEmpty(_item.children)) {
        _item.children = _item.children.filter(col => !col.hide)
      }
      visibleColumns.push(_item)
    })
    setColumns(visibleColumns)
    setTimeout(calcTheadHeight, 100)
  }

  useEffect(() => {
    initData()
  }, [propCols])

  const setLocalTableConfig = cols => {
    // let configableCols = filter(cols, col => !col.fixed)
    const config = cols.map(configCol => {
      const _config = {
        key: configCol.key,
        width: configCol.width,
        hide: configCol.hide,
      }
      if (!isEmpty(configCol.children)) {
        _config.children = configCol.children.map(_item => ({
          key: _item.key,
          width: _item.width,
          hide: _item.hide,
        }))
      }
      return _config
    })
    console.debug(`tableConfig_${configKey}`, config)
    localStorage.setItem(`tableConfig_${configKey}`, JSON.stringify(config))
  }

  const ConfigWithResizableTable = ({ width, height, scroll } = {}) => (
    <>
      {showConfig && (
        <div
          onClick={() => {
            ConfigModal.PromiseThen({
              columns: configColumns,
              onOk: cols => {
                setLocalTableConfig(cols)
                initData()
              },
              onReset: () => {
                localStorage.removeItem(`tableConfig_${configKey}`)
                initData()
              },
            })
          }}
          style={{
            cursor: 'pointer',
            position: 'absolute',
            right: 0,
            top: 0,
            height: 35,
            width: 35,
            zIndex: 10,
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            border: '1px solid #e8e8e8',
            backgroundColor: '#fafafa',
          }}
        >
          <SettingOutlined />
        </div>
      )}
      <ResizableTable
        {...props}
        // 以下内容不可被覆盖
        style={{ height, width }}
        columns={[
          showIndex && {
            key: 'index',
            title: '序号',
            width: 50,
            sysWidth: 50,
            className: 'text-center!',
            fixed: 'left',
            render: (_, __, index) => index + 1 + (pagination ? (pagination.current - 1) * pagination.pageSize : 0),
          },
          ...columns,
        ].filter(Boolean)}
        pagination={false}
        scroll={{
          // ...scroll,
          // 有scrollY的情况下，table会隐藏滚动条 ，但实际只在有数据的情况下需要隐藏
          y: isEmpty(dataSource) ? undefined : (height || scroll?.y || 500) - tHeadHeight,
        }}
        onResize={col => {
          console.debug(col)
          // 找到这一列并且更新
          const index = findIndex(columns, { key: col.key })
          columns[index].width = col.width
          setLocalTableConfig(columns)
          setColumns([...columns])
          calcTheadHeight()
        }}
      />
    </>
  )

  return (
    <div className={`flex-grow-1 pos-relative flex flex-col ${className}`}>
      <div className='flex-grow-1' ref={tableWrapperRef}>
        {autoSizeHeight ? (
          <AutoSizer>
            {({ width, height }) => {
              return ConfigWithResizableTable({ width, height })
            }}
          </AutoSizer>
        ) : (
          ConfigWithResizableTable({ scroll })
        )}
      </div>
      {(pagination || beforePagination) && (
        <div className='flex-items-center flex-justify-between pt10px flex'>
          {<span>{beforePagination}</span>}
          {pagination && <Pagination className='flex-none' {...pagination} />}
        </div>
      )}
    </div>
  )
}

export default ConfigableTable
